<?php
namespace CongoOpenSDK;

require_once(dirname(__FILE__) . '/Cipher.php');
require_once(dirname(__FILE__) . '/Request.php');

class OpenApiException extends \Exception
{
}

class OpenApi{
    public const ACCESSTOKEN = '123456';
    public const FORMAT = 'json';
    private const REQUEST_ENCRYPT = 'true';
    private const RESPONSE_ENCRYPT = 'true';

    static public function getConfig() {
        return include(dirname(__FILE__) . '/conf.php');
    }

    static public function execute($data, $method, $header = null, $version = '1.0') {
        $config = self::getConfig();
        if (empty($config['APP_KEY']) || empty($config['APP_SECRET']) || empty($config['GATEWAY']) || empty($config['PRIVATE_KEY']) || empty($config['PUBLIC_KEY']) || empty($config['SERVER_PUBLIC_KEY'])) {
            throw new \Exception("some request parameter is null");
        }

        $params = array(
            'appKey' => $config['APP_KEY'],
            'accessToken' => self::ACCESSTOKEN,
            'method' => $method,
            'version' => $version,
            'timestamp' => time() * 1000,
            'format' => self::FORMAT,
            'requestEncrypt' => self::REQUEST_ENCRYPT,
            'responseEncrypt' => self::RESPONSE_ENCRYPT,
        );

        if (is_array($data)) {
            $data = json_encode($data);
        }
        $aesKey = AES::getRandomKey();
        if (self::REQUEST_ENCRYPT || self::REQUEST_ENCRYPT === 'true') {
            $params['param'] = AES::encrypt($data, $aesKey, $config['APP_KEY']);
            $params['ak'] = RSA::privateKeyEncrypt($aesKey, $config['PRIVATE_KEY']);
        } else {
            $params['param'] = urlencode($data);
            $params['ak'] = $aesKey;
        }
        $params['sign'] = self::sign($params);

        $paramsStr = self::buildParamStr($params);
        $response = Request::post($config['GATEWAY'], $paramsStr, null, $header);
        if (!$response['succ']) {
            throw new OpenApiException("网络连接错误" . json_encode($response, JSON_UNESCAPED_UNICODE));
            ;
        }
        $result = json_decode($response['result'], true);

        if ($result['apiCode'] != 200) {
            error_log("网关请求错误: " . json_encode($result, JSON_UNESCAPED_UNICODE) . " \n", 0);
            throw new OpenApiException("网关请求错误" . json_encode($result, JSON_UNESCAPED_UNICODE));
        }

        if (self::RESPONSE_ENCRYPT || self::RESPONSE_ENCRYPT === 'true') {
            $servAesKey = RSA::publicKeyDecrypt($result['apiAk'], $config['SERVER_PUBLIC_KEY']);
            $decrypt = AES::decrypt($result['apiData'], $servAesKey, $config['APP_KEY']);
        } else {
            $decrypt = $result['apiData'];
        }
        return $decrypt;
    }

    public static function sign($params, $key = '') {
        $params = self::paraFilterSign($params);
        $sign = self::createLinkString($params);
        return md5($sign . $key);
    }

    public static function paraFilterSign($params) {
        $result = array();
        foreach ($params as $key => $value) {
            if ($value === null || $value === '') {
                continue;
            }
            $result[$key] = $value;
        }
        return $result;
    }

    public static function createLinkString($params) {
        ksort($params);
        $s = '';
        foreach ($params as $key => $value) {
            $s .= $key . $value;
        }
        return $s;
    }

    public static function buildParamStr($params) {
        $s = '';
        foreach ($params as $key => $value) {
            $s .= $key . '=' . $value . '&';
        }
        $s = rtrim($s, '&');
        return $s;
    }
}
?>
